<?php

if(!isset($_REQUEST["system.classLocation"])) {
    $_REQUEST["system.classLocation"] = "classes/";
}

if(!isset($_REQUEST["system.resourceLocation"])) {
    $_REQUEST["system.resourceLocation"] = "config/";
}

$classLocation = $_REQUEST["system.classLocation"];

require_once($classLocation . "Pageley/Util/ClassLoader.php");
require_once($classLocation . "Pageley/Util/SystemClassLoader.php");
require_once($classLocation . "Pageley/Util/Map.php");
require_once($classLocation . "Pageley/Util/ArrayMap.php");
require_once($classLocation . "Pageley/Util/String.php");
require_once($classLocation . "Pageley/Util/File.php");
require_once($classLocation . "Pageley/Util/NoSuchClassException.php");

/**
 * Represents the system.
 * 
 * <p>By default, System has the following properties:<p>
 * <ul>
 * 	<li>operatingSystem: Windows or Unix (= Unix, Linux or Mac OS)</li>
 * 	<li>file.delimiter: the character dilimiting paths in a list with multiple
 * 	paths</li>
 * 	<li>file.seperator: the character seperating the different directories
 * 	in a path</li>
 * </ul>
 * 
 * @package be.appcraft.util
 * @version $Revision: 1.2 $
 * 
 * @author Stijn Van Bael
 * @since 1.0
 *
 */
class Pageley_Util_System {
	
	private static $INSTANCE;
	
	/**
	 * A list of system properties
	 *
	 * @var Map
	 */
	private $properties;
	
	/**
	 * The ClassLoader to use to load classes.
	 *
	 * @var ClassLoader
	 */
	private $classLoader;
	
	/**
	 * Creates a new System
	 */
	private function __construct() {
		$this->classLoader = new Pageley_Util_SystemClassLoader();
		$this->properties = new Pageley_Util_ArrayMap();
		if(stristr(PHP_OS, "win") && !stristr(PHP_OS, "darwin")) {
			// Windows
			$this->setProperty("operatingSystem", "Windows");
			$this->setProperty("file.delimiter", ";");
			$this->setProperty("file.separator", "\\");
		} else {
			// All the others (Unix, Linux, Mac OS)
			$this->setProperty("operatingSystem", "Unix");
			$this->setProperty("file.delimiter", ":");
			$this->setProperty("file.separator", "/");
		}
	}
	
	/**
	 * Returns the only instance of System
	 *
	 * @return System
	 */
	public static function getInstance() {
		if(self::$INSTANCE === null) {
			self::$INSTANCE = new Pageley_Util_System();
		}
		return self::$INSTANCE;
	}
	
	/**
	 * Gets the property with the specified name.
	 *
	 * @param string $name: name of the property to get
	 * @return the property with the specified name, or null if the property
	 * does not exist.
	 */
	public function getProperty($name) {
		$value = $this->properties->get($name);
		if($value === null) {
			$value = $_REQUEST[$name];
		}
		return $value;
	}
	
	public function pathToResourceName($path) {
        $classLocation = $_REQUEST["system.classLocation"];
        $resourceLocation = $_REQUEST["system.resourceLocation"];
        if(Pageley_Util_String::startsWith($path, $classLocation)) {
            $path = Pageley_Util_String::substring($path, Pageley_Util_String::length($classLocation));
        } else if(Pageley_Util_String::startsWith($path, $resourceLocation)) {
            $path = Pageley_Util_String::substring($path, Pageley_Util_String::length($resourceLocation));
        }
		$fileDelimiter = $this->getProperty("file.delimiter");
		$includes = split($fileDelimiter, ini_get("include_path"));
		$resourceName = null;
		foreach($includes as $include) {
			$include = Pageley_Util_String::replace($include, "\\", "/");
			if(Pageley_Util_String::startsWith($path, $include . "/")) {
				$name = Pageley_Util_String::substring($path, Pageley_Util_String::length($include) + 1);
				if($resourceName === null || Pageley_Util_String::length($name) < Pageley_Util_String::length($resourceName)) {
					$resourceName = $name;
				}
			}
		}
		if($resourceName === null) {
			$resourceName = $path;
		}
		$resourceName = Pageley_Util_String::replace($resourceName, "/", "_");
        if(Pageley_Util_String::endsWith($resourceName, ".php")) {
            $resourceName = Pageley_Util_String::substring($resourceName, 0, Pageley_Util_String::length($resourceName) - 4);
        }
		return $resourceName;
	}
	
	/**
	 * Sets the property with the specified name.
	 *
	 * @param string $name: name of the property to set
	 * @param string $value: the new value of the property
	 */
	public function setProperty($name, $value) {
		return $this->properties->put($name, $value);
	}
	
	/**
	 * Sets the ClassLoader to load classes.
	 *
	 * @param ClassLoader $classLoader: the new ClassLoader to use 
	 */
	public function setClassLoader($classLoader) {
		$this->classLoader = $classLoader;
	}
	
	/**
	 * Loads the class with the specified name.
	 *
	 * @param string $className: name of the class to load
	 */
	public function loadClass($className) {
		$this->classLoader->loadClass($className);
	}
    
    public function loadConfig($configName) {
		$this->classLoader->loadConfig($configName);
	}
	
	public function addImportedResource($resource) {
		$this->importedResources->add($resource);
	}
	
	public function getImportedResources() {
		return $this->importedResources;
	}
	
	public static function runMain($runnable) {
		try {
			global $argv;
			if($argv !== null) {
				foreach($argv as $argument) {
					echo "processing " . $argument . "\n";
					if(Pageley_Util_String::contains($argument, "=")) {
						$key = Pageley_Util_String::substringBefore($argument, "=");
						$value = Pageley_Util_String::substringAfter($argument, "=");
						$_REQUEST[$key] = $value;
					}
				}
			}
			$runnable->runMain();
			exit(0);
		} catch(Exception $e) {
			echo $e;
			exit(1);
		}
	}
}

// Create a hook to manipulate class loading
function __autoload($className) {
	Pageley_Util_System::getInstance()->loadClass($className);
}

function handleError($errno, $errstr, $errfile, $errline) {
	throw new Exception("Error " . $errno . ": " . $errstr, $errno);
}

date_default_timezone_set(date_default_timezone_get());

set_error_handler("handleError", E_ALL ^ E_NOTICE);
